/* * Copyright 2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ratpack.jdbctx.internal; import org.h2.jdbcx.JdbcDataSource; import org.junit.Assert; import ratpack.exec.Blocking; import ratpack.exec.Operation; import ratpack.func.Block; import ratpack.jdbctx.Transaction; import ratpack.test.exec.ExecHarness; import ratpack.util.Exceptions; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Example { private static DataSource txDs; private static Transaction tx; public static void main(String[] args) throws Exception { JdbcDataSource ds = new JdbcDataSource(); ds.setURL("jdbc:h2:mem:transactionExamples;DB_CLOSE_DELAY=-1"); txDs = Transaction.dataSource(ds); tx = Transaction.create(ds::getConnection); try (Connection connection = txDs.getConnection()) { try (Statement statement = connection.createStatement()) { statement.executeUpdate("CREATE TABLE tbl (value VARCHAR(50)) "); } } List<Block> examples = Arrays.asList( Example::singleTransactionExample, Example::singleTransactionRollbackExample, Example::nestedTransactionExample, Example::nestedTransactionRollbackExample, () -> manualTransactionExample(true), () -> manualTransactionExample(false) ); try (ExecHarness harness = ExecHarness.harness()) { for (Block example : examples) { harness.execute(Operation.of(example)); reset(); } } } private static void reset() throws SQLException { try (Connection connection = txDs.getConnection()) { connection.createStatement().execute("DELETE FROM tbl"); } } private static Operation insert(String value) { return Blocking.op(() -> { try (Connection connection = txDs.getConnection()) { connection.createStatement().execute("INSERT INTO tbl (value) VALUES (" + value + ")"); } }); } private static Block assertValues(String... expected) { return () -> Blocking.get(() -> { try (Connection connection = txDs.getConnection()) { Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT value FROM tbl;"); List<String> actual = new ArrayList<>(); while (resultSet.next()) { actual.add(resultSet.getString(1)); } return actual; } }) .then(actual -> Assert.assertEquals(Arrays.asList(expected), actual)); } // BEGIN EXAMPLES private static void singleTransactionExample() { tx.wrap(insert("1")).then(assertValues("1")); } private static void singleTransactionRollbackExample() { RuntimeException exception = new RuntimeException("1"); tx.wrap( insert("1") .next(() -> { throw exception; }) ) .onError(e -> { Assert.assertSame(e, exception); Operation.of(assertValues()).then(); }) .then(() -> { throw new IllegalStateException("operation should have failed"); }); } private static void nestedTransactionExample() { tx.wrap( insert("1") .next(tx.wrap(insert("2"))) ) .then(assertValues("1", "2")); } private static void nestedTransactionRollbackExample() { RuntimeException exception = new RuntimeException("1"); tx.wrap( insert("1") .next( tx.wrap( insert("2") .next(() -> { throw exception; }) ) // recover from the error, and insert something else .mapError(e -> insert("3").then()) ) ) .then(assertValues("1", "3")); } private static void manualTransactionExample(boolean fail) { tx.begin() .next(insert("1")) .next(() -> { if (fail) { throw new RuntimeException("!"); } }) .onError(e -> tx.rollback().then(() -> { throw Exceptions.toException(e); }) ) .next(tx.commit()) .onError(e -> assertValues().map(Operation::of).then()) .then(assertValues("1")); } }